package org.lemon.transport.context.service.queue.provider;

import org.lemon.transport.context.service.discovery.ServiceInfoProvider;
import org.lemon.transport.context.service.queue.*;
import org.lemon.transport.context.data.queue.message.ProtoQueueMessage;
import org.lemon.transport.context.service.queue.rabbit.*;
import org.lemon.transport.context.service.queue.setting.*;
import org.server.transport.gen.SessionProto.*;
import org.server.transport.gen.TransportProto.*;
import org.springframework.stereotype.Component;


@Component
public class RabbitMqTransportQueueFactory {

    private final RabbitMqSettings rabbitMqSettings;
    private final ServiceInfoProvider serviceInfoProvider;

    private final QueueCoreSettings coreSettings;
    private final QueueRuleEngineSettings ruleEngineSettings;
    private final QueueRemoteJsInvokeSettings jsInvokeSettings;
    private final QueueTransportAuthApiSettings transportAuthApiSettings;
    private final QueueTransportApiSettings transportApiSettings;
    private final QueueTransportNotificationSettings transportNotificationSettings;

    private final QueueAdmin coreAdmin;
    private final QueueAdmin ruleEngineAdmin;
    private final QueueAdmin jsExecutorAdmin;
    private final QueueAdmin transportTokenAuthAdmin;
    private final QueueAdmin transportX509CretAuthAdmin;
    private final QueueAdmin transportMqttCredAuthAdmin;
    private final QueueAdmin transportApiAdmin;
    private final QueueAdmin notificationAdmin;

    public RabbitMqTransportQueueFactory(RabbitMqSettings rabbitMqSettings,
                                         ServiceInfoProvider serviceInfoProvider,
                                         QueueCoreSettings coreSettings,
                                         QueueRuleEngineSettings ruleEngineSettings,
                                         QueueRemoteJsInvokeSettings jsInvokeSettings,
                                         QueueTransportAuthApiSettings transportAuthApiSettings,
                                         QueueTransportApiSettings transportApiSettings,
                                         QueueTransportNotificationSettings transportNotificationSettings,
                                         RabbitMqQueueArguments queueArguments) {
        this.rabbitMqSettings = rabbitMqSettings;
        this.serviceInfoProvider = serviceInfoProvider;
        this.coreSettings = coreSettings;
        this.ruleEngineSettings = ruleEngineSettings;
        this.jsInvokeSettings = jsInvokeSettings;
        this.transportAuthApiSettings = transportAuthApiSettings;
        this.transportApiSettings = transportApiSettings;
        this.transportNotificationSettings = transportNotificationSettings;

        this.coreAdmin = new RabbitMqAdmin(rabbitMqSettings, queueArguments.getCoreArgs());
        this.ruleEngineAdmin = new RabbitMqAdmin(rabbitMqSettings, queueArguments.getRuleEngineArgs());
        this.jsExecutorAdmin = new RabbitMqAdmin(rabbitMqSettings, queueArguments.getJsExecutorArgs());
        this.transportTokenAuthAdmin = new RabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportAuthArgs());
        this.transportX509CretAuthAdmin = new RabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportAuthArgs());
        this.transportMqttCredAuthAdmin = new RabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportAuthArgs());
        this.transportApiAdmin = new RabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportApiArgs());
        this.notificationAdmin = new RabbitMqAdmin(rabbitMqSettings, queueArguments.getTransportApiArgs());
    }

    /**
     * token 认证请求模板
     *
     * @return
     */
    public QueueRequestTemplate<ProtoQueueMessage<ValidateDeviceTokenRequestMsg>, ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> createTokenAuthRequestTemplate() {

        QueueProducer<ProtoQueueMessage<ValidateDeviceTokenRequestMsg>> producerTemplate =
                new RabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, transportAuthApiSettings.getTokenAuthRequestsTopic());

        QueueConsumer<ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> consumerTemplate =
                new RabbitMqConsumerTemplate<>(transportApiAdmin, rabbitMqSettings,
                        transportAuthApiSettings.getTokenAuthResponsesTopic() + "." + serviceInfoProvider.getServiceId(),
                        message -> new ProtoQueueMessage<>(message.getKey(),
                                ValidateDeviceCredentialsResponseMsg.parseFrom(message.getData()), message.getHeaders()));
        DefaultQueueRequestTemplate.DefaultQueueRequestTemplateBuilder<ProtoQueueMessage<ValidateDeviceTokenRequestMsg>, ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> templateBuilder =
                DefaultQueueRequestTemplate.builder();

        templateBuilder.queueAdmin(transportTokenAuthAdmin);
        templateBuilder.requestTemplate(producerTemplate);
        templateBuilder.responseTemplate(consumerTemplate);
        templateBuilder.maxPendingRequests(transportAuthApiSettings.getMaxPendingRequests());
        templateBuilder.maxRequestTimeout(transportAuthApiSettings.getMaxRequestsTimeout());
        templateBuilder.pollInterval(transportAuthApiSettings.getResponsePollInterval());
        return templateBuilder.build();
    }

    /**
     * X509Cert 认证请求模板
     *
     * @return
     */
    public QueueRequestTemplate<ProtoQueueMessage<ValidateDeviceX509CertRequestMsg>, ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> createX509AuthRequestTemplate() {

        QueueProducer<ProtoQueueMessage<ValidateDeviceX509CertRequestMsg>> producerTemplate =
                new RabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, transportAuthApiSettings.getX509CertAuthRequestsTopic());

        QueueConsumer<ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> consumerTemplate =
                new RabbitMqConsumerTemplate<>(transportApiAdmin, rabbitMqSettings,
                        transportAuthApiSettings.getX509CertAuthResponsesTopic() + "." + serviceInfoProvider.getServiceId(),
                        message -> new ProtoQueueMessage<>(message.getKey(),
                                ValidateDeviceCredentialsResponseMsg.parseFrom(message.getData()), message.getHeaders()));
        DefaultQueueRequestTemplate.DefaultQueueRequestTemplateBuilder<ProtoQueueMessage<ValidateDeviceX509CertRequestMsg>, ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> templateBuilder =
                DefaultQueueRequestTemplate.builder();

        templateBuilder.queueAdmin(transportX509CretAuthAdmin);
        templateBuilder.requestTemplate(producerTemplate);
        templateBuilder.responseTemplate(consumerTemplate);
        templateBuilder.maxPendingRequests(transportAuthApiSettings.getMaxPendingRequests());
        templateBuilder.maxRequestTimeout(transportAuthApiSettings.getMaxRequestsTimeout());
        templateBuilder.pollInterval(transportAuthApiSettings.getResponsePollInterval());
        return templateBuilder.build();
    }

    /**
     * MqttCred 认证请求模板
     *
     * @return
     */
    public QueueRequestTemplate<ProtoQueueMessage<ValidateBasicMqttCredRequestMsg>, ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> createMqttCredAuthRequestTemplate() {

        QueueProducer<ProtoQueueMessage<ValidateBasicMqttCredRequestMsg>> producerTemplate =
                new RabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, transportAuthApiSettings.getMqttCredAuthRequestsTopic());

        QueueConsumer<ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> consumerTemplate =
                new RabbitMqConsumerTemplate<>(transportApiAdmin, rabbitMqSettings,
                        transportAuthApiSettings.getMqttCredAuthResponsesTopic() + "." + serviceInfoProvider.getServiceId(),
                        message -> new ProtoQueueMessage<>(message.getKey(),
                                ValidateDeviceCredentialsResponseMsg.parseFrom(message.getData()), message.getHeaders()));
        DefaultQueueRequestTemplate.DefaultQueueRequestTemplateBuilder<ProtoQueueMessage<ValidateBasicMqttCredRequestMsg>, ProtoQueueMessage<ValidateDeviceCredentialsResponseMsg>> templateBuilder =
                DefaultQueueRequestTemplate.builder();

        templateBuilder.queueAdmin(transportMqttCredAuthAdmin);
        templateBuilder.requestTemplate(producerTemplate);
        templateBuilder.responseTemplate(consumerTemplate);
        templateBuilder.maxPendingRequests(transportAuthApiSettings.getMaxPendingRequests());
        templateBuilder.maxRequestTimeout(transportAuthApiSettings.getMaxRequestsTimeout());
        templateBuilder.pollInterval(transportAuthApiSettings.getResponsePollInterval());
        return templateBuilder.build();
    }

    /**
     * api 请求模板
     *
     * @return
     */
    public QueueRequestTemplate<ProtoQueueMessage<TransportApiRequestMsg>, ProtoQueueMessage<TransportApiResponseMsg>> createTransportApiRequestTemplate() {

        QueueProducer<ProtoQueueMessage<TransportApiRequestMsg>> producerTemplate =
                new RabbitMqProducerTemplate<>(transportApiAdmin, rabbitMqSettings, transportApiSettings.getRequestsTopic());

        QueueConsumer<ProtoQueueMessage<TransportApiResponseMsg>> consumerTemplate =
                new RabbitMqConsumerTemplate<>(transportApiAdmin, rabbitMqSettings,
                        transportApiSettings.getResponsesTopic() + "." + serviceInfoProvider.getServiceId(),
                        message -> new ProtoQueueMessage<>(message.getKey(),
                                TransportApiResponseMsg.parseFrom(message.getData()), message.getHeaders()));
        DefaultQueueRequestTemplate.DefaultQueueRequestTemplateBuilder<ProtoQueueMessage<TransportApiRequestMsg>, ProtoQueueMessage<TransportApiResponseMsg>> templateBuilder =
                DefaultQueueRequestTemplate.builder();

        templateBuilder.queueAdmin(transportApiAdmin);
        templateBuilder.requestTemplate(producerTemplate);
        templateBuilder.responseTemplate(consumerTemplate);
        templateBuilder.maxPendingRequests(transportApiSettings.getMaxPendingRequests());
        templateBuilder.maxRequestTimeout(transportApiSettings.getMaxRequestsTimeout());
        templateBuilder.pollInterval(transportApiSettings.getResponsePollInterval());
        return templateBuilder.build();
    }

    /**
     * 发送至规则引擎的消息生成者
     *
     * @return
     */
    public QueueProducer<ProtoQueueMessage<ToRuleEngineMsg>> createRuleEngineMessageProducer() {
        return new RabbitMqProducerTemplate<>(ruleEngineAdmin, rabbitMqSettings, ruleEngineSettings.getTopic());
    }

    /**
     * 发送至应用服务的消息生成者
     *
     * @return
     */
    public QueueProducer<ProtoQueueMessage<ToCoreMsg>> createCoreMessageProducer() {
        return new RabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic());
    }

    /**
     * 消息通知的消费者
     *
     * @return
     */
    public QueueConsumer<ProtoQueueMessage<ToTransportMsg>> createTransportNotificationsConsumer() {
        return new RabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings,
                transportNotificationSettings.getNotificationsTopic() + "." + serviceInfoProvider.getServiceId(),
                message -> new ProtoQueueMessage<>(message.getKey(), ToTransportMsg.parseFrom(message.getData()), message.getHeaders()));
    }

    private void destroy() {
        if (coreAdmin != null) {
            coreAdmin.destroy();
        }
        if (ruleEngineAdmin != null) {
            ruleEngineAdmin.destroy();
        }
        if (transportApiAdmin != null) {
            transportApiAdmin.destroy();
        }
        if (notificationAdmin != null) {
            notificationAdmin.destroy();
        }
    }
}
